﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls.Classes;
using System.Drawing;
using System.Reflection;
using Silvermoon.Visuals;
using System.IO;
using Silvermoon.Animations;
using Silvermoon.Core;
using Silvermoon.Controls.Interfaces;
using Silvermoon.Controls.Base;

namespace Silvermoon.Controls
{
    /// <summary>
    /// Control that hosts controls having a toolbar and a keyboard panel to access.
    /// </summary>
    public class Window : FormBase, ICompositeControl, IForm, IInputEventBehavior
    {
        #region fields

        private RectangleVisual background;
        private Color color;
        private static KeyboardPanel keyboard;
        private bool showKeyboard;
        private ToolbarBase toolbar;
        private Color inputBgColor;

        private List<Control> controls;
        private Panel controlsPanel;
        #endregion
        #region ctor

        public Window()
        {
            Margin = new Margin(0);
            controlsPanel = new Panel();

            controls = new List<Control>();
            controls.Add(controlsPanel);

            Height = KeyboardPanel.KeyboardHeight - 4;
        }

        public override void Dispose()
        {
            base.Dispose();
        }

        #endregion
        #region Props

        protected int ToolbarHeight
        {
            get
            {
                if (Toolbar != null)
                {
                    Toolbar.PreLoad();
                    return toolbar.Height;
                }
                else return 0;
            }
        }

        /// <summary>
        /// Gets or sets the color of the window.
        /// </summary>
        public Color Color
        {
            get { return color; }
            set
            {
                if (color != value)
                {
                    color = value;
                    OnColorChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the color for the input background.
        /// </summary>
        public Color InputBgColor
        {
            get { return inputBgColor.IsEmpty ? SysColors.BackgroundColor : inputBgColor; }
            set
            {
                if (keyboard != null) keyboard.Color = value;
                inputBgColor = value;
            }
        }


        protected static KeyboardPanel GetKeyboard()
        {
            if (keyboard == null) keyboard = new KeyboardPanel();
            keyboard.Flags = ControlFlags.IgnoreClipping;
            return keyboard;
        }

        /// <summary>
        /// Gets the KeyboardPanel.
        /// </summary>
        public KeyboardPanel Keyboard
        {
            get
            {
                if (keyboard == null)
                {
                    keyboard = GetKeyboard();
                    keyboard.Bounds = new Rectangle(0, Height - keyboard.Height + 4 - ToolbarHeight, Width, keyboard.Height);
                    keyboard.Visible = false;
                    OnShowKeyboardChanged(ShowKeyboard);
                }
                return keyboard;
            }
        }


        /// <summary>
        /// Gets or sets whether to show the toolbar.
        /// </summary>
        public bool ShowToolbar
        {
            get { return toolbar != null ? toolbar.Visible : false; }
            set
            {
                if (toolbar == null) value = false;
                if (ShowToolbar != value)
                {
                    toolbar.Visible = value;
                    OnShowToolbarChanged();
                }
            }
        }

        /// <summary>
        /// Gets or sets the toolbar.
        /// </summary>
        public ToolbarBase Toolbar
        {
            get { return toolbar; }
            set
            {
                if (toolbar != value)
                {
                    if (toolbar != null) ((IToolbar)toolbar).Window = null;
                    toolbar = value;
                    if (toolbar != null) ((IToolbar)toolbar).Window = this;
                    Invalidate(InvalidationFlag.LayoutAppearance);
                }
            }
        }

        /// <summary>
        /// Gets or sets whether the keyboard is visible:
        /// </summary>
        public bool ShowKeyboard
        {
            get { return showKeyboard; }
            set
            {
                if (Screen.Current.Landscape) value = false;
                if (showKeyboard != value)
                {
                    if (value) Keyboard.Color = InputBgColor;
                    showKeyboard = value;
                    OnShowKeyboardChanged(value);
                }
            }
        }

        public override IList<Control> Controls { get { return controlsPanel.Controls; } }

        protected internal override IList<Control> SubControls { get { return controls; } }

        #endregion
        #region methods

        protected virtual void OnColorChanged()
        {
            Invalidate(InvalidationFlag.Color);
        }

        protected override void PreLayout()
        {
            base.PreLayout();
            if (CheckFlag(InvalidationFlag.Size | InvalidationFlag.Appearance | InvalidationFlag.Margin))
            {

                if (toolbar != null) controls.Remove(toolbar);
                int toolbarHeight = 0;
                if (ShowToolbar)
                {
                    if (toolbar != null) controls.Add(toolbar);

                    IToolbar tb = (IToolbar)toolbar;
                    toolbarHeight = toolbar.Height - tb.OverlaySize;
                    toolbar.Bounds = new Rectangle(0, Height - toolbar.Height, Width, toolbar.Height);
                }
                int keyboardHeight = 0;
                if (ShowKeyboard && keyboard != null)
                {
                    keyboardHeight = keyboard.Height;
                    keyboard.Bounds = new Rectangle(0, Height - keyboardHeight - toolbarHeight, Width, keyboard.Height);
                }
                controlsPanel.Bounds = new Rectangle(0, 0, Width, Height - toolbarHeight - keyboardHeight);
                ClientBounds = controlsPanel.Bounds;

            }
        }
        protected override void OnLayout()
        {
            if (CheckFlag(InvalidationFlag.Color | InvalidationFlag.Appearance))
            {
                if (Color != Color.Empty)
                {
                    if (background == null) background = new RectangleVisual();
                    background.Color = Color;
                    Visuals = new Visual[] { background };
                }
                else
                {
                    if (background != null)
                    {
                        background.Dispose();
                        background = null;
                    }
                    Visuals = null;
                }
            }
            if (background != null) background.Size = Size;


            base.OnLayout();
        }

        protected override void OnSizeChanged()
        {
            ShowKeyboard = false;
            base.OnSizeChanged();
        }

        protected virtual void OnShowKeyboardChanged(bool value)
        {
            if (value)
            {
                Flags = ControlFlags.IgnoreClipping;
                Keyboard.Visible = true;
                controls.Remove(Keyboard);
                controls.Insert(1, Keyboard);
                if (Visible)
                {
                    Transition.InvokeAsync(Keyboard, TransitionMode.SwipeInFromBottom | TransitionMode.FadeIn, 250, 0, (s, e) => Invalidate(InvalidationFlag.Appearance));
                }
            }
            else
            {
                Flags = ControlFlags.DisableHitTest | ControlFlags.IgnoreClipping;
                Invalidate(InvalidationFlag.Appearance);
                if (Visible && keyboard != null && keyboard.Visible)
                {
                    Transition.InvokeAsync(Keyboard, TransitionMode.SwipeOutToBottom | TransitionMode.FadeOut, 350, 0, (s, ex) => { controls.Remove(Keyboard); });
                }
                else if (keyboard != null)
                {
                    controls.Remove(keyboard);
                    Invalidate(InvalidationFlag.Appearance);
                }
            }
            if (ShowKeyboardChanged != null) ShowKeyboardChanged(this, EventArgs.Empty);
        }

        /// <summary>
        /// Occurs when the visibility of the toolbar changes.
        /// </summary>
        protected virtual void OnShowToolbarChanged()
        {
            if (!ShowToolbar) ShowKeyboard = false;
            if (ShowToolbarChanged != null) ShowToolbarChanged(this, EventArgs.Empty);
            Invalidate(InvalidationFlag.LayoutAppearance);
        }

        public void SendToBack()
        {
            Screen.SendToBack(this);
        }

        public void BringToFron()
        {
            Screen.BringToFront(this);
        }


        protected override void OnHiding()
        {
            ShowKeyboard = false;
            base.OnHiding();
        }

        #endregion
        #region events

        /// <summary>
        /// Occurs when the visibility of the toolbar changes.
        /// </summary>
        public event EventHandler ShowToolbarChanged;
        public event EventHandler ShowKeyboardChanged;

        public event System.Windows.Forms.KeyEventHandler KeyDown;
        public event System.Windows.Forms.KeyEventHandler KeyUp;

        #endregion
        #region IInputEventBehavior Members

        public virtual void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
        {
            if (KeyDown != null) KeyDown(this, e);
        }

        public virtual void OnKeyUp(System.Windows.Forms.KeyEventArgs e)
        {
            if (KeyUp != null) KeyUp(this, e);
        }

        public virtual void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
        {
        }

        public virtual void OnGotFocus()
        {
        }

        public virtual void OnLostFocus()
        {
        }

        public virtual bool IsFocused
        {
            get { return false; }
        }

        public virtual bool CanFocus
        {
            get { return false; }
        }

        #endregion
    }
}
